package kino.command;

import kino.client.KinoClient;
import kino.common.KinoConstant;
import kino.database.KinoDB;
import kino.object.KinoObject;
import kino.object.KinoObjectTypeEnum;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@KinoCommandEnable
public class SetCommand extends AbstractKinoCommand{

    @Override
    public String doExecute(KinoClient client, String... argv) {
        KinoDB kinoDB = client.getDb();
        Map<String, KinoObject> dict = kinoDB.getDict();
        Map<String, Object> extParam = client.getExtParam();

        if (extParam != null) {
            // 扩展参数 NX 和 XX
            // NX 需要 key不存在
            // EX 需要 key已存在
            String nxOrXx = (String) extParam.get("NXorXX");
            if (nxOrXx != null && nxOrXx.equals("NX") && dict.containsKey(argv[0])) {
                return commandEncoder.error("NX参数下key已存在执行失败");
            }
            if (nxOrXx != null && nxOrXx.equals("XX") && !dict.containsKey(argv[0])) {
                return commandEncoder.error("XX参数下key不已存在执行失败");
            }
            // 扩展参数 EX PX 设置过期时间
            // EX 按秒设置
            // PX 按毫秒设置
            String exAndPx = (String)extParam.get("EXorPX");
            Integer time = (Integer)extParam.get("time");
            if (exAndPx != null && time != null) {
                if (exAndPx.equals("EX")) {
                    time *= 1000;
                }
                kinoDB.setExpire(argv[0], System.currentTimeMillis() + time);
            }
        }
        // 插入数据库
        KinoObject kinoObject = new KinoObject(KinoObjectTypeEnum.KINO_STRING);
        kinoObject.setObj(argv[1]);
        dict.put(argv[0], kinoObject);
        return KinoConstant.OK;
    }

    @Override
    public Integer getArgc() {
        return 2;
    }

    @Override
    public String getCommandName() {
        return "set";
    }

    @Override
    public boolean aofFlag() {
        return true;
    }

    @Override
    public boolean hasExtParam() {
        return true;
    }

    @Override
    protected ExtParamParseResult doExtParamParse(String... argv) {
        ExtParamParseResult paramParseResult = new ExtParamParseResult();
        Map<String, Object> extParam = new HashMap<>();
        paramParseResult.setSuccess(true);
        paramParseResult.setExtParam(extParam);
        for (int i = this.getArgc(); i < argv.length;i++) {
            String param = argv[i];
            String upParam = param.toUpperCase(Locale.ROOT);
            if (upParam.equals("NX") || upParam.equals("XX")) {
                extParam.put("NXorXX", upParam);
            } else if (upParam.equals("EX") || upParam.equals("PX")) {
                extParam.put("EXorPX", upParam);
                // 该参数后面应该再跟一个数字，后面不够提示错误
                if (i == argv.length - 1) {
                    paramParseResult.setSuccess(false);
                    paramParseResult.setErrorMsg(KinoConstant.syntaxerr);
                    return paramParseResult;
                }
                String nextParam = argv[i + 1];
                // 下一个参数不是数字的情况，提示错误
                if (!isNumeric(nextParam)) {
                    paramParseResult.setSuccess(false);
                    paramParseResult.setErrorMsg(commandEncoder.error("命令" + upParam + "后面需要跟数字"));
                    return paramParseResult;
                }
                i++;
                extParam.put("time", Integer.valueOf(nextParam));
            } else {
                paramParseResult.setSuccess(false);
                paramParseResult.setErrorMsg(KinoConstant.syntaxerr);
                return paramParseResult;
            }
        }
        return paramParseResult;
    }

}
